﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Linq;
using System.Xml;

using iPhoneUI.Shell;

namespace iPhoneUI.Widgets
{
    public class ButtonGrid : Widget
    {
        private IImage m_pushedOverlayImage;

        private IImage m_backgroundImage;

        private IImageButton m_scrollUpButton;
        private IImageButton m_scrollDownButton;

        private int stepX = 57;
        private int stepY = 71;
        private int startX = 10;

        public ButtonGrid()
        {
            NavigationUpImage = "nav_up_blue.png";
            NavigationDownImage = "nav_down_blue.png";
            m_pushedOverlayImage = ShellConfig.CreatePerPixelAlphaImage("AppIconOverlay.png");

            ButtonSize = 48;
            TopPadding = 2;

            Buttons = new List<IImageButton>();
        }

        public string BackgroundImageName { get; set; }

        public int TopPadding { get; set; }

        public bool UseSmallIcons { get; set; }

        public IList<IImageButton> Buttons { get; set; }

        public string NavigationUpImage { get; set; }

        public string NavigationDownImage { get; set; }

        public int ButtonSize { get; set; }

        protected override void OnSetOwner()
        {
            m_scrollUpButton = new IImageButton();
            m_scrollUpButton.SetOwner(Owner);
            m_scrollUpButton.Image = ShellConfig.CreatePerPixelAlphaImage(NavigationUpImage);
            m_scrollUpButton.SizeToImage();
            m_scrollUpButton.Clicked += new EventHandler(m_scrollUpButton_Clicked);

            m_scrollDownButton = new IImageButton();
            m_scrollDownButton.SetOwner(Owner);
            m_scrollDownButton.Image = ShellConfig.CreatePerPixelAlphaImage(NavigationDownImage);
            m_scrollDownButton.SizeToImage();
            m_scrollDownButton.Clicked += new EventHandler(m_scrollDownButton_Clicked);

            // filter out any buttons that have a cmdlet that says that it is not valid
            Buttons = Buttons.Except(Buttons.Where(b => b.CmdLet != null && b.CmdLet.IsValid == false)).ToList();

            foreach (IImageButton b in Buttons)
                InitializeButton(b);

            if (string.IsNullOrEmpty(BackgroundImageName) == false)
            {
                m_backgroundImage = ShellConfig.CreatePerPixelAlphaImage(BackgroundImageName);
                SetInitialSize(new Size(Size.Width, m_backgroundImage.Size().Height));
            }

            stepX = Owner.ScaleX(stepX);
            stepY = Owner.ScaleY(stepY);
            startX = Owner.ScaleX(startX);

            base.OnSetOwner();
        }

        private void InitializeButton(IImageButton b)
        {
            b.SetOwner(Owner);
            if(string.IsNullOrEmpty(b.ImageName) == false)
                b.Image = ShellConfig.CreatePerPixelAlphaImage(b.ImageName);
            
            if (string.IsNullOrEmpty(b.OverlayImageName) == false)
                b.OverlayImage = ShellConfig.CreatePerPixelAlphaImage(b.OverlayImageName);
            
            if (string.IsNullOrEmpty(b.IconFilePath) == false)
                b.Icon = UseSmallIcons ? Shortcut.GetSmallIcon(b.IconFilePath) : Shortcut.GetIcon(b.IconFilePath);

            b.PushedOverlayImage = m_pushedOverlayImage;

            b.SizeToImage();
        }

        protected override void Layout()
        {
            m_scrollUpButton.Location = new Point(Size.Width - (m_scrollUpButton.Size.Width - 1), ClientArea.Bottom - m_scrollUpButton.Size.Height + 1);
            m_scrollDownButton.Location = new Point(Location.X + 1, ClientArea.Bottom - m_scrollDownButton.Size.Height + 1);

            int y = Location.Y + TopPadding;
            int x = startX;
            foreach (IImageButton b in Buttons)
            {
                b.Location = new Point(x, y);
                x += stepX;

                // if the next button won't fit start a new row
                if (x + ButtonSize > Size.Width)
                {
                    x = startX;
                    y += stepY;
                }
            }

            base.Layout();
        }

        private void m_scrollDownButton_Clicked(object sender, EventArgs e)
        {
            foreach (ButtonWidget b in Buttons)
                b.Location = new Point(b.Location.X, b.Location.Y - stepY);

            Update();
        }

        private void m_scrollUpButton_Clicked(object sender, EventArgs e)
        {
            foreach (ButtonWidget b in Buttons)
                b.Location = new Point(b.Location.X, b.Location.Y + stepY);

            Update();
        }

        public bool CanScrollUp
        {
            get
            {
                return Buttons.Any(b => b.Location.Y < Location.Y);
            }
        }

        public bool CanScrollDown
        {
            get
            {
                return Buttons.Any(b => b.ClientArea.Bottom > ClientArea.Bottom);
            }
        }

        public void Clear()
        {
            Buttons.DisposeAll();
            Buttons.Clear();
        }

        public override void OwnerMouseDown(int x, int y)
        {
            if (HitTest(x, y))
            {
                if (CanScrollDown)
                    m_scrollDownButton.OwnerMouseDown(x, y);

                if (CanScrollUp)
                    m_scrollUpButton.OwnerMouseDown(x, y);

                foreach (ButtonWidget b in Buttons)
                    b.OwnerMouseDown(x, y);
            }
        }

        public override void OwnerMouseUp(int x, int y)
        {
            if (CanScrollDown)
                m_scrollDownButton.OwnerMouseUp(x, y);

            if (CanScrollUp)
                m_scrollUpButton.OwnerMouseUp(x, y);

            foreach (ButtonWidget b in Buttons.Where(b => b.Pushed))
                b.OwnerMouseUp(x, y);
        }

        protected override void OnDraw(Canvas canvas, Rectangle clipBounds)
        {
            if (m_backgroundImage != null)
                canvas.AlphaBlend(m_backgroundImage, ClientArea);

            // don't paint buttons that are outside of the ClientArea due to scrolling
            foreach (Widget b in Buttons.Where(b => ClientArea.Contains(b.ClientArea)))
                b.Draw(canvas, clipBounds);

            if (CanScrollUp)
                m_scrollUpButton.Draw(canvas, clipBounds);

            if (CanScrollDown)
                m_scrollDownButton.Draw(canvas, clipBounds);
        }

        protected override void OnDispose()
        {
            Clear();

            m_pushedOverlayImage = null;
            m_backgroundImage = null;

            m_scrollUpButton.SafeDispose();
            m_scrollDownButton.SafeDispose();

            base.OnDispose();
        }
    }
}
